import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

public class DataGatherer extends Thread
{
  /*
   * ** total pages retrieved ** average words per page ** average urls per
   * page ** keyword average hits hits per page total hits
   *  ** page limit: ** average parse time per page ** total running time
   */

  private int pagesRetrieved;

  private double avgUrlsPerPage, avgWordsPerPage;

  private ArrayList<Integer> wordsPerPages;

  private ArrayList<Integer> urlsPerPages;

  private int totalUrls, totalWords;

  private long totalParseTime;

  private double startTime;

  private HashMap<String, Integer> keywords = new HashMap<String, Integer>();

  private ConcurrentLinkedQueue<PageData> pageDataQueue;

  private ConcurrentLinkedQueue<ReportData> reportDataQueue;

  public static int PAGE_LIMIT = 50;

  public DataGatherer(double startTime,
      ConcurrentLinkedQueue<PageData> pageDataQueue,
      ConcurrentLinkedQueue<ReportData> reportDataQueue)
  {
    this.startTime = startTime;
    this.pageDataQueue = pageDataQueue;
    this.reportDataQueue = reportDataQueue;
    wordsPerPages = new ArrayList<Integer>();
    urlsPerPages = new ArrayList<Integer>();
    pagesRetrieved = 0;
    avgWordsPerPage = 0;
    avgUrlsPerPage = 0;
    totalUrls = 0;
    totalWords = 0;
    totalParseTime = 0;
    initKeywords();
  }
  
  public void setStartTime(long l)
  {
    if(l > 0)
      startTime = l;
      
  }

  public void countWords(String s)
  {
    int count = 0;
    String[] noTags = deHTML(s);

    for (String noTagString : noTags)
    {
      count += noTagString.split("\\s+").length;
    }

    totalWords += count;
    wordsPerPages.add(count);
  }

  private String[] deHTML(String s)
  {
    String[] result = s.split("<.*?>\\s*");
    return result;
  }

  /** ************************* Getters & Setters *************************** */

  public ArrayList<Map.Entry<String, Integer>> getKeywordData()
  {
    Iterator<Map.Entry<String, Integer>> i = keywords.entrySet().iterator();
    ArrayList<Map.Entry<String, Integer>> data = new ArrayList<Map.Entry<String, Integer>>();

    while (i.hasNext())
    {
      data.add(i.next());
    }

    return data;
  }

  public double getStartTime()
  {
    return startTime;
  }

  public synchronized int getPagesRetrieved()
  {
    return pagesRetrieved;
  }

  public synchronized double getAvgWordsPerPage()
  {
    calcAvgWords();
    return avgWordsPerPage;
  }

  public synchronized double getAvgUrlsPerPage()
  {
    calcAvgUrls();
    return avgUrlsPerPage;
  }

  public synchronized long getParseTimePerPage()
  {
    return totalParseTime / pagesRetrieved;
  }

  /** ************************* Mutators *************************** */

  public synchronized void incrementPageCount()
  {
    pagesRetrieved = getPagesRetrieved() + 1;
  }

  public synchronized void addUrlsCount(int urlsCount)
  {
    urlsPerPages.add(urlsCount);
    totalUrls += urlsCount;
  }

  public synchronized void calcAvgUrls()
  {
    avgUrlsPerPage = totalUrls / (double) urlsPerPages.size();
  }

  public synchronized void calcAvgWords()
  {
    avgWordsPerPage = totalWords / (double) wordsPerPages.size();
  }

  public synchronized void countKeywords(String page)
  {
    for (String keyword : keywords.keySet())
    {
      int keywordCount = page.split(keyword.toLowerCase()).length
          + page.split(keyword.substring(0, 0).toUpperCase()
              + keyword.substring(1)).length;
      keywords.put(keyword, keywords.get(keyword) + keywordCount - 1);
    }
  }

  public synchronized void addToTotalParseTime(long time)
  {
    totalParseTime += time;
  }

  public void setPageLimit(int i)
  {
    DataGatherer.PAGE_LIMIT = i;
  }

  /** *************************** Misc *************************** */

  public void run()
  {
    while (getPagesRetrieved() < DataGatherer.PAGE_LIMIT)
    {
      if (!pageDataQueue.isEmpty())
      {
        PageData pageData = pageDataQueue.poll();

        incrementPageCount();
        // System.out.println(getPagesRetrieved());
        addToTotalParseTime(pageData.getParseTime());
        countWords(pageData.getPageContent());
        countKeywords(pageData.getPageContent());
        addUrlsCount(pageData.getUrlCount());

        reportDataQueue.add(new ReportData(getPagesRetrieved(),
            getAvgUrlsPerPage(), getAvgWordsPerPage(),
            getParseTimePerPage(), getStartTime(), this.getKeywordData()));
      }
    }
  }

  /** *************************** Helpers *************************** */

  private void initKeywords()
  {
    String[] keywordArray = { "pearl", "Jam", "american", "rock", "band",
        "formed", "seattle", "washington", "integer", "albatross" };

    for (String keyword : keywordArray)
    {
      keywords.put(keyword, 0);
    }
  }

}
